﻿using Ionic.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace CodeGeneratorBootstrap.Util
{
    public class CZip
    {
        private Ionic.Zip.ZipFile zipFile;

        public CZip() : this(null) { }
        public CZip(FileInfo zipFilePath)
        {
            if (zipFilePath != null)
            {
                if (zipFilePath.Name.IndexOf(".zip") == -1)
                    zipFilePath = new FileInfo(zipFilePath.FullName + ".zip");
                if (zipFilePath.Exists)
                    this.zipFile = Ionic.Zip.ZipFile.Read(zipFilePath.FullName);
                else
                    this.zipFile = new Ionic.Zip.ZipFile(zipFilePath.FullName);
            }
        }

        public void AddZipFileEntry(string fileName)
        {
            this.AddZipFileEntry(new FileInfo(fileName), null, null);
        }
        public void AddZipFileEntry(string fileName, string password)
        {
            this.AddZipFileEntry(new FileInfo(fileName), null, password);
        }
        public void AddZipFileEntry(string fileName, DirectoryInfo dir)
        {
            this.AddZipFileEntry(new FileInfo(fileName), dir, null);
        }
        public void AddZipFileEntry(string fileName, DirectoryInfo dir, string password)
        {
            this.AddZipFileEntry(new FileInfo(fileName), dir, password);
        }

        public void AddZipFileEntry(FileInfo fileName)
        {
            this.AddZipFileEntry(fileName, null, null);
        }
        public void AddZipFileEntry(FileInfo fileName, string password)
        {
            this.AddZipFileEntry(fileName, null, password);
        }
        public void AddZipFileEntry(FileInfo fileName, DirectoryInfo dir)
        {
            this.AddZipFileEntry(fileName, dir, null);
        }
        public void AddZipFileEntry(FileInfo fileName, DirectoryInfo dir, string password)
        {
            fileName.Refresh();
            if (fileName == null || !fileName.Exists)
                throw new FileNotFoundException();
            this.zipFile.Password = password;
            this.zipFile.AddItem(fileName.FullName, dir == null ? string.Empty : dir.ToString());
        }

        public void AddZipDirectoryEntry(DirectoryInfo dir)
        {
            this.AddZipDirectoryEntry(dir, null, null);
        }
        public void AddZipDirectoryEntry(DirectoryInfo dir, string password)
        {
            this.AddZipDirectoryEntry(dir, null, password);
        }
        public void AddZipDirectoryEntry(DirectoryInfo dir, DirectoryInfo dirInZip)
        {
            this.AddZipDirectoryEntry(dir, dirInZip, null);
        }
        public void AddZipDirectoryEntry(DirectoryInfo dir, DirectoryInfo dirInZip, string password)
        {
            if (!dir.Exists)
                throw new DirectoryNotFoundException();
            this.zipFile.Password = password;
            this.zipFile.AddItem(dir.FullName, dirInZip == null ? dir.Name : dirInZip.ToString());
        }
        public void AddZipDirectoryEntryWithAES256_Encrypt(string filePath, string targetPath, string dirInArch, string password)
        {
            if (!new FileInfo(filePath).Exists) throw new FileNotFoundException();
            using (ZipFile zip = new ZipFile())
            {
                // add this map file into the "images" directory in the zip archive 
                zip.Encryption = EncryptionAlgorithm.WinZipAes256;
                zip.Password = password;
                zip.AddFile(filePath, dirInArch);
                zip.Save(targetPath);
            }
        }

        public void Save()
        {
            if (this.Name == string.Empty)
                throw new FileNotFoundException();
            else
            {
                this.zipFile.Comment = "This zip archive was updated " + System.DateTime.Now.ToString();
                this.zipFile.Save();
            }
        }
        public string Name
        {
            set
            {
                if (value.IndexOf(".zip") == -1)
                    value = value + ".zip";
                this.zipFile.Name = value;
            }
            get
            {
                return this.zipFile.Name;
            }
        }

        public static void ZipMultiFile(ICollection<string> FileNames, string ZipFileName)
        {
            using (ZipFile zip = new ZipFile())
            { // add this map file into the "images" directory in the zip archive 
                foreach (string filename in FileNames)
                {
                    zip.AddFile(filename);
                }
                zip.Save(ZipFileName);
            }
        }

        public static void CreateZipFileEntry(string zipFilePath, string fileName)
        {
            CZip.CreateZipFileEntry(new FileInfo(zipFilePath), new FileInfo(fileName), null, null);
        }
        public static void CreateZipFileEntry(string zipFilePath, string fileName, string password)
        {
            CZip.CreateZipFileEntry(new FileInfo(zipFilePath), new FileInfo(fileName), null, password);
        }
        public static void CreateZipFileEntry(string zipFilePath, string fileName, DirectoryInfo dir)
        {
            CZip.CreateZipFileEntry(new FileInfo(zipFilePath), new FileInfo(fileName), dir, null);
        }
        public static void CreateZipFileEntry(string zipFilePath, string fileName, DirectoryInfo dir, string password)
        {
            CZip.CreateZipFileEntry(new FileInfo(zipFilePath), new FileInfo(fileName), dir, password);
        }
        public static void CreateZipFileEntry(FileInfo zipFilePath, FileInfo zipFile)
        {
            CZip.CreateZipFileEntry(zipFilePath, zipFile, null, null);
        }
        public static void CreateZipFileEntry(FileInfo zipFilePath, FileInfo zipFile, string password)
        {
            CZip.CreateZipFileEntry(zipFilePath, zipFile, null, password);
        }
        public static void CreateZipFileEntry(FileInfo zipFilePath, FileInfo zipFile, DirectoryInfo dir)
        {
            CZip.CreateZipFileEntry(zipFilePath, zipFile, dir, null);
        }
        public static void CreateZipFileEntry(FileInfo zipFilePath, FileInfo zipFile, DirectoryInfo dir, string password)
        {
            CZip zip = new CZip(zipFilePath);
            zip.AddZipFileEntry(zipFile, dir, password);
            zip.Save();
        }

        public static void CreateZipDirectoryEntry(string zipFilePath, DirectoryInfo dir)
        {
            CZip.CreateZipDirectoryEntry(new FileInfo(zipFilePath), dir, null, null);
        }
        public static void CreateZipDirectoryEntry(string zipFilePath, DirectoryInfo dir, string password)
        {
            CZip.CreateZipDirectoryEntry(new FileInfo(zipFilePath), dir, null, password);
        }
        public static void CreateZipDirectoryEntry(string zipFilePath, DirectoryInfo dir, DirectoryInfo dirInZip)
        {
            CZip.CreateZipDirectoryEntry(new FileInfo(zipFilePath), dir, dirInZip, null);
        }
        public static void CreateZipDirectoryEntry(string zipFilePath, DirectoryInfo dir, DirectoryInfo dirInZip, string password)
        {
            CZip.CreateZipDirectoryEntry(new FileInfo(zipFilePath), dir, dirInZip, password);
        }
        public static void CreateZipDirectoryEntry(FileInfo zipFilePath, DirectoryInfo dir)
        {
            CZip.CreateZipDirectoryEntry(zipFilePath, dir, null, null);
        }
        public static void CreateZipDirectoryEntry(FileInfo zipFilePath, DirectoryInfo dir, string password)
        {
            CZip.CreateZipDirectoryEntry(zipFilePath, dir, null, null);
        }
        public static void CreateZipDirectoryEntry(FileInfo zipFilePath, DirectoryInfo dir, DirectoryInfo dirInZip)
        {
            CZip.CreateZipDirectoryEntry(zipFilePath, dir, dirInZip, null);
        }
        public static void CreateZipDirectoryEntry(FileInfo zipFilePath, DirectoryInfo dir, DirectoryInfo dirInZip, string password)
        {
            CZip zip = new CZip(zipFilePath);
            zip.AddZipDirectoryEntry(dir, dirInZip, password);
            zip.Save();
        }
        public static void ExtractZipWithPassword(string ZipFile, string PathToExtract, string Password)
        {
            using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(ZipFile))
            {
                foreach (ZipEntry e in zip)
                {
                    e.ExtractWithPassword(PathToExtract, ExtractExistingFileAction.OverwriteSilently, Password);
                }
            }
        }
    }
}
